<template>
  <div
    :id="config ? config.title : 'chartv'"
    class="comp-chart"
    :class="chartType"
    style="height: 100%;"
  >
    <gis-map-public
      v-if="isGisView"
      :id="Number(config.dataId)"
      :project-id="Number(config.projectId)"
    />
    <!-- geomap -->
    <!-- <geo-map
      v-if="isGeo"
      ref="geomap"
      :config="config"
      :chart-maps-real="chartMapsReal"
    /> -->
    <!-- graph组件 -->
    <!-- <template v-if="isGraph">
      <graph
        :chart-type="parsedChartType"
        :config="config"
        @lineGraphNodeDragend="
          (value) =>
            $emit('chartevent', { name: 'lineGraphNodeDragend', value })
        "
        @lineGraphNodeClick="
          (value) => $emit('chartevent', { name: 'graphNodeClick', value })
        "
        @dagreNodeClick="
          (value) => $emit('chartevent', { name: 'graphNodeClick', value })
        "
      />
    </template> -->

    <component
      :is="customChartCompName"
      v-if="customChartCompName"
      :config="config"
      :theme="chartTheme"
    />
  </div>
</template>
<script lang="ts">
// import { isArray, isUndefined } from 'lodash'\
import { GRAPH_ARRAY } from '@/config/contant'
import { isFunction, debounce, isEqual } from 'lodash'
import {
  PieChart,
  DonutChart,
  // RoseChart,
  BarChart,
  GroupBarChart,
  StackBarChart,
  // PercentageStackBarChart,
  LineChart,
  AreaRangeChart,
  BoxLineChart,
  // StepLineChart,
  // PathChart,
  ScatterChart,
  // MatrixChart,
  // AreaChart,
  StackedAreaChart,
  // PercentStackedAreaChart,
  // ParallelCoordinates,
  // ChoroplethMap,
  // ScalableBarChart,
  HeatmapMatrixChart,
  DensityDataBarChart,
  DensityDataAreaChart,
  DualAxesChart,
  DiffBarChart,
  BubbleScatterChart,
  GaugeChart,
  WordCloud,
  // @ts-ignore
} from '@zjlabvis/vis-charts'
// @ts-ignore
import { GeographicMap } from '@zjlabvis/vis-charts-plus'
import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
// import GeoMap from '@/components/chart/GeoMap.vue'
// import Graph from '@/components/chart/Graph.vue'
import GisMapPublic from '@/components/gis/public/GisMapPublic.vue'
// import Cge4RegionComp from '@/components/chart/cge4-region.vue'
import { KeyValueStore } from '../interface/grid-item-data-interface'

function areaRangeChartMapFuc(container: any, options: any) {
  console.log(options.realChartType)
  return options.realChartType === 'BoxLineChart'
    ? new BoxLineChart(container, options)
    : new AreaRangeChart(container, options)
}

function barChartMapFun(container: any, options: any) {
  return options.realChartType === 'diffBarChart'
    ? new DiffBarChart(container, options)
    : new BarChart(container, options)
}

const chartMapsReal: KeyValueStore = {
  pieChart: PieChart,
  donutChart: DonutChart,
  barChart: barChartMapFun,
  groupBarChart: GroupBarChart,
  stackBarChart: StackBarChart,
  lineChart: LineChart,
  areaRangeChart: areaRangeChartMapFuc,
  scatterplot: ScatterChart,
  areaChart: StackedAreaChart,
  // parallelCoordinates: ParallelCoordinates,
  heatmapMatrix: HeatmapMatrixChart,
  densityDataBarChart: DensityDataBarChart,
  densityDataAreaChart: DensityDataAreaChart,
  dualAxesChart: DualAxesChart,
  diffBarChart: DiffBarChart,
  bubbleScatterChart: BubbleScatterChart,
  gaugeChart: GaugeChart,
  wordCloud: WordCloud,
}

// demo chart
const demoChartMap: KeyValueStore = {
  CGE4Region: 'cge4-region-comp',
}

const THEME_MAPPING: any = {
  light: 'nebula-white',
  blue: 'nebula-white',
  textured: 'nebula-white',
  simple: 'nebula-white',
  dark: 'nebula-dark',
  nebula: 'nebula-dark',
}

@Component({
  components: {
    GeographicMap,
    // GeoMap,
    // Graph,
    GisMapPublic,
    // Cge4RegionComp,
  },
})
export default class Chart extends Vue {
  /** 组件名称 */
  name: string = 'chart'

  /** 真实chart实例 */
  compInstance: any = null

  /** 组件类型 */
  @Prop({
    type: [Array, String],
    default(): string {
      return 'pieChart'
    },
  })
  'chartType'!: string | Array<string>

  /** 组件配置项 */
  @Prop({
    type: Object,
    default(): Object {
      return {
        value: [],
      }
    },
  })
  config!: KeyValueStore

  /** 尺寸 */
  size: Array<number> = []

  /** 是否是地图组件，地图组件是vue组件，初始化方式不一样 */
  private isGeo = false
  /** 是否是graph组件 */
  private isGraph = false
  /** 是否展示graph */
  private isShowGraph = false

  private chartMapsReal = chartMapsReal

  private isCustomChart: boolean = false
  private customChartCompName: string = ''

  /** 地图类型监听，发生改变时销毁之前实例 */
  @Watch('chartType', { immediate: true })
  getChartType() {
    if (this.$el) {
      const chartType = Array.isArray(this.chartType)
        ? this.chartType[1]
        : this.chartType
      this.isGraph = GRAPH_ARRAY.includes(this.parsedChartType) //  更新是否为graph组件状态
      if (demoChartMap[chartType]) {
        this.customChartCompName = demoChartMap[chartType]
        return
      }
      if (this.compInstance && isFunction(this.compInstance.destroy)) {
        this.compInstance.destroy()
        this.compInstance = new chartMapsReal[chartType](this.$el, this.config)
      }
    }
  }

  /**
   * 如 BoxLineChart 和 AreaRangeChart 这种被整合到一个类型中的chart
   * 除了 chartType 还需要监听 config.realChartType
   * */
  @Watch('config.realChartType', { immediate: true })
  getRealChartType(newValue: string, oldValue: string) {
    if (
      [newValue, oldValue].some((value) =>
        ['BoxLineChart', 'diffBarChart'].includes(value)
      )
    ) {
      this.getChartType()
    }
  }

  /** 配置监听, 配置发生改变则更新组件 */
  @Watch('config', { deep: true, immediate: true })
  getConfig(nConfig: any, oConfig: any) {
    this.size = this.config.size
    if (this.compInstance) {
      const chartType = Array.isArray(this.chartType)
        ? this.chartType[1]
        : this.chartType // 兼容性获取chartType
      if (
        chartType === 'heatmapMatrix' &&
        Array.isArray(this.config.colors) &&
        (this.config.colors as Array<string>)[0]
      ) {
        const color = (this.config.colors as Array<string>)[0]
        this.config.legendBasicColor =
          this.config.singleColor === false ? false : color
      }

      const newConfig = { ...this.config }
      if (this.chartType.includes('wordCloud')) {
        newConfig.wordField = this.config.labelKey
        newConfig.weightField = this.config.valueKey
        newConfig.imageMask = this.config?.imageMaskObj?.url
      }
      this.compInstance.update({
        ...newConfig,
        xAxis: {
          ...newConfig.xAxis,
          label: {
            autoRotate: this.config.xAxisLabelIsRotate,
            rotate: this.config.xAxisLabelIsRotate ? -Math.PI / 4 : null,
            style: {
              textAlign: this.config.xAxisLabelIsRotate ? 'right' : 'center',
            },
          },
        },
        theme: THEME_MAPPING[this.config.themeSetting?.theme || 'light'],
      })
      // wordCloud 组件在放大/缩小时需要调用内部g2的render才能保证文本渲染正常，有图片遮罩时不用考虑，g2内部会处理
      if (
        chartType === 'wordCloud' &&
        !this.config.imageMask &&
        nConfig.size &&
        oConfig.size &&
        isEqual(nConfig.size, oConfig.size)
      ) {
        this.$nextTick(() => {
          this.compInstance.realChart?.render()
        })
      }
      // 元素点击
      if (this.config.realChartType !== 'diffBarChart') {
        this.compInstance?.$on(
          'element:click',
          debounce((event: any) => {
            this.$emit('chartevent', { name: 'selectedChange', event })
          }, 50)
        )
      }
      // by zhangfanfan 先暂时注释掉，后续可能还会再开启
      // if (this.config.realChartType === 'diffBarChart') {
      //   this.compInstance.$on('drag-bar', (value: any) => {
      //     this.$emit('chartevent', { name: 'dragBar', value })
      //   })
      // }
    }
  }

  /** vue钩子：mounted, 初始化组件 */
  mounted() {
    this.init()
  }

  /** 获取this引用 */
  getRef() {
    return this
  }

  /** 设置组件属性 */
  setAttr(key: string, value: any) {
    this.compInstance.$set(key, value)
  }
  /** 获取组件属性 */
  getAttr(key: string) {
    return this.compInstance.$get(key)
  }

  /** 用于外部确认是否为vue chart 组件 */
  get isVueChart() {
    return true
  }

  /** 是否为 GIS视图同步过来的组件 */
  get isGisView() {
    return this.parsedChartType === 'gisView'
  }

  private get parsedChartType(): string {
    return Array.isArray(this.chartType) ? this.chartType[1] : this.chartType
  }

  private get chartTheme(): string {
    return THEME_MAPPING[this.config.themeSetting?.theme || 'light']
  }

  /**
   * 主题色需要单独配置指定的chart
   */
  /*
  private get isSingleColorMode() {
    return !(
      Array.isArray(this.config.yAxisAttribute) &&
      this.config.yAxisAttribute.length > 1
    )
  }
  */

  /** 初始化组件实例 */
  init() {
    if (!this.chartType) {
      return
    }

    const chartType = Array.isArray(this.chartType)
      ? this.chartType[1]
      : this.chartType // 兼容性获取chartType
    this.isGeo = chartType === 'geographicMap' //  更新是否为地图组件状态
    this.isGraph = GRAPH_ARRAY.includes(this.parsedChartType) //  更新是否为graph组件状态

    // 特殊处理heatmapMaritix
    if (
      chartType === 'heatmapMatrix' &&
      Array.isArray(this.config.colors) &&
      (this.config.colors as Array<string>)[0]
    ) {
      const color = (this.config.colors as Array<string>)[0]
      this.config.legendBasicColor =
        this.config.singleColor === false ? false : color
    }

    if (demoChartMap[chartType]) {
      this.customChartCompName = demoChartMap[chartType]
      return
    }

    // 渲染chart
    if (this.isGeo || this.isGisView) {
      // 地图组件是vue组件，渲染机制不一样，需特殊处理
      if (this.isGeo) {
        this.$nextTick(() => {
          // this.$emit('chartinit', this.$refs.geomap)
        })
      }
    } else if (this.isGraph) {
      this.isShowGraph = false // 状态切换用于销毁之前的graph实例
    } else if (chartMapsReal[chartType]) {
      this.config.value = this.config.value || [] // value 不存在时传空数组
      /*
      if (
        this.isSingleColorMode &&
        Array.isArray(this.config.colors) &&
        this.config.colors.length > 0
      ) {
        ;[this.config.color] = this.config.colors
      }
      */
      if (chartType === 'dualAxesChart' && this.config.value.length === 0) {
        this.config.value = [[], []] // 柱线混合空数据模式特殊，否则报错
      }
      if (this.chartType.includes('wordCloud')) {
        this.config.wordField = this.config.labelKey
        this.config.weightField = this.config.valueKey
        this.config.imageMask = this.config?.imageMaskObj?.url
      }
      this.$nextTick(() => {
        this.compInstance = new chartMapsReal[chartType](this.$el, {
          ...this.config,
          xAxis: {
            label: {
              autoRotate: this.config.xAxisLabelIsRotate,
              rotate: this.config.xAxisLabelIsRotate ? -Math.PI / 4 : null,
              style: {
                textAlign: this.config.xAxisLabelIsRotate ? 'right' : 'center',
              },
            },
          },
          theme: THEME_MAPPING[this.config.themeSetting?.theme || 'light'],
        })
        // console.log(this.config, this.compInstance)
        this.$emit('chartinit', this.compInstance)
      })
      // 元素点击
      if (this.config.realChartType !== 'diffBarChart') {
        // element click 事件加 interactions 配置会同一时间触发多次事件，这里加 debounce控制
        this.compInstance?.$on(
          'element:click',
          debounce((event: any) => {
            this.$emit('chartevent', { name: 'selectedChange', event })
          }, 50)
        )
      }
    } else {
      console.error('chartType set error:', chartType, chartMapsReal)
    }
  }

  changeSize(size: number[]) {
    // config改变时会重新render，在不render的基础上改动容器的size
    this.size = size
  }

  beforeDestroy() {
    if (this.compInstance && isFunction(this.compInstance.destroy)) {
      this.compInstance.destroy()
    }
  }
}
</script>
<style lang="less" scoped>
.comp-chart {
  margin: auto;
  overflow: hidden;
  z-index: 300;
}
</style>

<style lang="less">
.background-div {
  bottom: 0;
  left: 0;
  pointer-events: none;
  position: absolute;
  right: 0;
  top: 0;
}

.legend-div {
  cursor: pointer;
  overflow: hidden;
  pointer-events: auto;
}

.legend-color {
  border: #aaa 1px solid;
}

.legend-text {
  display: inline-block;
  font-size: 12px;
  margin-left: 10px;
  vertical-align: top;
}

.to-left-div {
  border-color: transparent #555 transparent transparent;
  border-style: solid;
  border-width: 10px 20px 10px 0;
  cursor: pointer;
  display: inline-block;
  height: 0;
  margin: 0 5px;
  pointer-events: auto;
  width: 0;
}

.to-left-div:hover {
  border-color: transparent #000 transparent transparent;
}

.to-right-div {
  border-color: transparent transparent transparent #555;
  border-style: solid;
  border-width: 10px 0 10px 20px;
  cursor: pointer;
  display: inline-block;
  height: 0;
  margin: 0 5px;
  pointer-events: auto;
  width: 0;
}

.to-right-div:hover {
  border-color: transparent transparent transparent #000;
}

.notclick {
  cursor: not-allowed;
}

.current-circle {
  border: #000 1px solid;
  border-radius: 50%;
  font-size: 10px;
  overflow: hidden;
  pointer-events: auto;
  position: absolute;
  text-align: center;
}

.title-div {
  bottom: 0;
  font-size: 32px;
  font-weight: bolder;
  left: 0;
  padding: 15px 40px;
  pointer-events: none;
  position: absolute;
  right: 0;
  top: 0;
}
</style>
